import asyncio
import json
import logging
from aiohttp import web
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCIceCandidate
from app.common.logger.customlogger import CustomLogger
from app.config import OperateYaml

logging.basicConfig(level=logging.INFO)

# 房间管理（roomId -> {userId: websocket}）
rooms = {}

# WebRTC 连接管理（userId -> RTCPeerConnection）
peer_connections = {}


async def websocket_handler(request):
    """
    处理 WebSocket 连接: ws://localhost:19090/rtc?roomId=xxx&userId=xxx
    """
    ws = web.WebSocketResponse()
    await ws.prepare(request)

    # 获取 roomId 和 userId
    room_id = request.query.get("roomId")
    user_id = request.query.get("userId")
    
    if not room_id or not user_id:
        await ws.close()
        return ws

    logging.info(f"用户 {user_id} 加入房间 {room_id}")

    # 加入房间
    if room_id not in rooms:
        rooms[room_id] = {}
    rooms[room_id][user_id] = ws

    await broadcast_message(room_id, "join", {"userId": user_id})

    try:
        async for msg in ws:
            if msg.type == web.WSMsgType.TEXT:
                print(msg)
                message = json.loads(msg.data)
                await handle_message(room_id, user_id, message)
            elif msg.type == web.WSMsgType.ERROR:
                logging.error(f"WebSocket 错误: {ws.exception()}")

    finally:
        # 断开连接时清理
        logging.info(f"用户 {user_id} 退出房间 {room_id}")
        #  通知房间内其他人退出
        await broadcast_message(room_id, "leave", {"userId": user_id})
        del rooms[room_id][user_id]
        if not rooms[room_id]:  # 如果房间为空，删除房间
            del rooms[room_id]
        await ws.close()

    return ws


async def handle_message(room_id, user_id, message):
    print(user_id)
    print(message)
    """
    处理 WebRTC 信令消息
    - { type: "offer" | "answer" | "candidate", userId: "xxx", data: {} }
    """
    msg_type = message.get("type")
    target_user_id = message.get("userId")  # 目标用户 ID（接收者）
    data = json.loads(message.get("data"))

    if not msg_type or not target_user_id or not data:
        logging.warning(f"无效的消息: {message}")
        return

    # 目标用户是否在线
    if target_user_id not in rooms.get(room_id, {}):
        logging.warning(f"用户 {target_user_id} 不在线，无法转发 {msg_type}")
        return

    # target_ws = rooms[room_id][target_user_id]

    target_ws = rooms[room_id][target_user_id]

    # 直接转发信令消息
    await target_ws.send_json({
        "type": msg_type,
        "userId": user_id,  # 发送者 ID
        "data": data
    })

    # **1. 处理 Offer（user_id 发送 offer，target_user_id 接收并回复 answer）**
    # if msg_type == "offer":
    #     logging.info(f"用户 {user_id} 向 {target_user_id} 发送 Offer")

    #     # 在 **target_user_id** 端（接收方）创建 RTCPeerConnection
    #     peer_connections[target_user_id] = RTCPeerConnection()
    #     pc = peer_connections[target_user_id]

    #     # 监听 ICE 候选
    #     @pc.on("icecandidate")
    #     async def on_ice_candidate(candidate):
    #         if candidate:
    #             await target_ws.send_json({
    #                 "type": "candidate",
    #                 "userId": target_user_id,  # 目标用户 ID
    #                 "data": {
    #                     "candidate": candidate.to_sdp(),
    #                     "sdpMid": candidate.sdpMid,
    #                     "sdpMLineIndex": candidate.sdpMLineIndex
    #                 }
    #             })

    #     # **在 target_user_id 端接收 offer 并设置远程描述**
    #     offer = RTCSessionDescription(sdp=data["sdp"], type="offer")
    #     await pc.setRemoteDescription(offer)

    #     # 生成 Answer 并设置本地描述
    #     answer = await pc.createAnswer()
    #     await pc.setLocalDescription(answer)

    #     # **发送 Answer 给 offer 发送者（user_id）**
    #     sender_ws = rooms[room_id][user_id]  # 获取 Offer 发送者的 WS 连接
    #     await sender_ws.send_json({
    #         "type": "answer",
    #         "userId": target_user_id,  # 这里是 target_user_id 发送 answer
    #         "data": {
    #             "sdp": pc.localDescription.sdp,
    #             "type": "answer"
    #         }
    #     })

    # # **2. 处理 Answer（user_id 现在应该接收 Answer 并设置远程描述）**
    # elif msg_type == "answer":
    #     if user_id not in peer_connections:
    #         logging.warning(f"用户 {user_id} 没有 RTCPeerConnection，无法设置 answer")
    #         return

    #     logging.info(f"用户 {user_id} 处理 {target_user_id} 的 Answer")
    #     pc = peer_connections[user_id]

    #     # **在 user_id 端设置远程描述**
    #     answer = RTCSessionDescription(sdp=data["sdp"], type="answer")
    #     await pc.setRemoteDescription(answer)

    # # **3. 处理 ICE Candidate**
    # elif msg_type == "candidate":
    #     if user_id not in peer_connections:
    #         logging.warning(f"用户 {user_id} 没有 RTCPeerConnection，无法设置 ICE Candidate")
    #         return

    #     logging.info(f"用户 {user_id} 处理 {target_user_id} 的 ICE Candidate")
    #     pc = peer_connections[user_id]
    #     candidate = RTCIceCandidate(
    #         component="rtp",
    #         foundation="0",
    #         protocol="udp",
    #         priority=0,
    #         port=0,
    #         ip="",
    #         type="host",
    #         sdp=data["candidate"],
    #         sdpMid=data["sdpMid"],
    #         sdpMLineIndex=data["sdpMLineIndex"]
    #     )
    #     await pc.addIceCandidate(candidate)


async def broadcast_message(room_id, msg_type, data):
    """
    广播消息到房间内所有用户
    """
    message = {
        "type": msg_type,
        "data": list(rooms[room_id].keys())
    }
    print(message)
    for user_id, ws in rooms[room_id].items():
        try:
            await ws.send_json(message)
        except Exception as e:
            logging.error(f"发送消息给 {user_id} 失败: {e}")

# 启动 WebSocket 服务器
app = web.Application()
app.router.add_get("/rtc", websocket_handler)
config = OperateYaml().read_yaml()
logger = CustomLogger(config['logger']['dir'], config['logger']['level']).getLogHandler()
app["logger"] = logger

if __name__ == '__main__':
    web.run_app(app, port=config['port'])
